package com.rongji.dfish.framework.service;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;

import javax.persistence.Id;

import org.springframework.beans.factory.annotation.Autowired;

import com.rongji.dfish.framework.dao.PubCommonDAO;

/**
 * 
 * @author DFish Team
 *
 * @param <T> 实体对象类型Entity
 * @param <ID> ID对象类型通常是String
 */
public abstract class BaseService<T, ID extends Serializable> {
	@Autowired
	protected PubCommonDAO pubCommonDAO;

	public PubCommonDAO getPubCommonDAO() {
		return pubCommonDAO;
	}

	public void setPubCommonDAO(PubCommonDAO pubCommonDAO) {
		this.pubCommonDAO = pubCommonDAO;
	}
	@SuppressWarnings("unchecked")
	public T find(ID id) {
		if(id==null){
			return null;
		}
		Class<?>entityClass=getEntiyType(getClass());
		String className=entityClass.getName();
		String idName=null;
		for(Method m:entityClass.getMethods()){
			if(m.getAnnotation(Id.class)!=null){
				String methodsName=m.getName();
				if(methodsName.startsWith("get")){
					idName=methodsName.substring(3);
					char c=idName.charAt(0);
					if(c>='A'&&c<='Z'){
						idName=((char)(c+32))+ idName.substring(1);
					}
				}
				break;
			}
		}
		return (T)pubCommonDAO.queryAsAnObject("FROM "+className+" t WHERE t."+idName+"=?", id);
	}
	/**
	 * 根据给定的ID列表 返回指定该ID指定的列表
	 * 如果其中，ID指定的数据不存在，返回结果List中，相对应的位置，为null
	 * 如果ID 有重复，返回结果也是有重复。但并不会进行数据库的多次查询
	 * 改方法将批量调用数据库根据主键查询的方法，形如
	 * SELECT t.xx FROM Xxx t WHERE t.id=? OR t.id=?;
	 * 每个批次默认不多于50个ID。超过，则进行下一批查询。
	 * @param id ID
	 * @return List
	 */
	public List<T> findAll(Collection<ID> id) {
		//TODO 实现
		return null;
	}
	private static Class<?> getEntiyType(Class<?>clz){
		Type genType = clz.getGenericSuperclass();
		if (!(genType instanceof ParameterizedType)) {
			throw new UnsupportedOperationException("can not recognize the entity TYPE of "+clz.getName());
		}
		
		Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
		if (params==null||params.length==0||!(params[0] instanceof Class)) {
			throw new UnsupportedOperationException("can not recognize the entity TYPE of "+clz.getName());
		}
		Class<?> entityClass= (Class<?>) params[0];
		return entityClass;
	}
	/**
	 * 利用hibernate默认的get方法获取对象
	 * 注意此方法，取出的对象如果进行了set操作，很可能会影响其他线程
	 * 并且不用显式调用update也可能会被写入到数据库。
	 * @param id
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public T get(ID id) {
		if(id==null){
			return null;
		}
		Class<?>entityClass=getEntiyType(getClass());
		return (T)pubCommonDAO.getHibernateTemplate().get(entityClass, id);
	}
	public void update(T entity) {
		pubCommonDAO.update(entity);
	}
	public<S extends T> void deleteAll(Collection<S> entities) {
		if(entities==null){
			return ;
		}
		pubCommonDAO.getHibernateTemplate().deleteAll(entities);
	}
	public void delete(T entity) {
		pubCommonDAO.delete(entity);
	}
	public void delete(ID id) {
		pubCommonDAO.delete(get(id));
	}
	public void save(T entity) {
		pubCommonDAO.save(entity);
	}
	
	public static final int BATCH_SIZE = 512;
	
	public static String getParamStr(int paramCount) {
		StringBuilder paramStr = new StringBuilder();
		boolean isFirst = true;
		for (int i = 0; i < paramCount; ++i) {
			if (isFirst) {
				isFirst = false;
			} else {
				paramStr.append(',');
			}
			paramStr.append('?');
		}
		return paramStr.toString();
	}
}
